﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Collections.ObjectModel;

namespace Kocic.RepositoryManagement
{
    /// <summary>
    /// Base class implementation for deferring changes to a data source.
    /// </summary>
    /// <typeparam name="TDataSource">The data source to defer changes to.</typeparam>
    /// <typeparam name="TDataObject">The base type of the data object(s) that are being deferred to the data source.</typeparam>
    public abstract class DataSourceDeferrer<TDataSource, TDataObject> : IDisposable
        where TDataSource : class
        where TDataObject : class
    {
        private static DataSourceDeferrer<TDataSource, TDataObject> _currentOperation;
        private Boolean _disposed = false;
        private TDataSource _dataSource;
        private ICollection<TDataObject> _objects = new Collection<TDataObject>();

        /// <summary>
        /// Creates an instance of the DataSourceDeferrer class.
        /// </summary>
        /// <param name="dataSource">An instance of the data source to which to defer changes to.</param>
        /// <exception cref="ArgumentNullException"></exception>
        protected DataSourceDeferrer(TDataSource dataSource)
        {
            if (dataSource == null)
            {
                throw new ArgumentNullException("Data source is null.", "dataSource");
            }

            _currentOperation = this;
            this._dataSource = dataSource;
        }

        /// <summary>
        /// Gets or sets a static reference to the the DataSourceDeferrer type.
        /// </summary>
        public static DataSourceDeferrer<TDataSource, TDataObject> DeferralOperation
        {
            get { return DataSourceDeferrer<TDataSource, TDataObject>._currentOperation; }
            set { DataSourceDeferrer<TDataSource, TDataObject>._currentOperation = value; }
        }

        /// <summary>
        /// Gets or sets the indicated value if the object has been disposed.
        /// </summary>
        protected Boolean Disposed
        {
            get { return this._disposed; }
            set { this._disposed = value; }
        }

        /// <summary>
        /// Gets or sets the instance of the data source.
        /// </summary>
        protected TDataSource DataSource
        {
            get { return this._dataSource; }
            set { this._dataSource = value; }
        }

        /// <summary>
        /// Gets a static reference of the collection of the data objects to defer.
        /// </summary>
        public static ICollection<TDataObject> DeferredObjects
        {
            get { return _currentOperation._objects; }
        }

        /// <summary>
        /// Gets a the data objects to defer.
        /// </summary>
        protected ICollection<TDataObject> InstanceDefferedObjects
        {
            get { return this._objects; }
        }

        #region IDisposable Members

        /// <summary>
        /// Releases resouces used by the data source deferrer.
        /// </summary>
        public void Dispose()
        {
            this.Dispose(true);
            GC.SuppressFinalize(this);
        }

        #endregion

        /// <summary>
        /// Disposes unmanaged resources.
        /// </summary>
        /// <param name="disposing">Value indicating if to invoke the method from the IDisposable.Dispose implementation or from the finalizer.</param>
        protected virtual void Dispose(Boolean disposing)
        {
            if (disposing)
            {
                this._disposed = true;
            }
        }
    }
}